function copyObj(obj) {
  //对于原始类型和常见的非值，直接返回原来值
  if ([NaN, null].includes(obj)) return obj;
  if (
    [
      "number",
      "string",
      "boolean",
      "null",
      "undefined",
      "function",
      "symbol",
    ].includes(typeof obj)
  ) {
    return obj;
  }

  const objCopy = Array.isArray(obj) ? [] : {};
  for (const key in obj) {
    objCopy[key] = typeof obj[key] === "object" ? copyObj(obj[key]) : obj[key];
  }
  return objCopy;
}
var obj1 = {
  name: "zhangsan",
  age: 18,
  details: {
    like: ["打篮球", "唱歌"],
    sex: 1,
    tags: [18, 23],
  },
};

console.log(copyObj(obj1));
console.log(JSON.stringify(obj1));

//   一维数据结构的深拷贝方法建议使用：Object.assign()；

// 二维数据结构及以上的深拷贝方法建议使用：JSON.parse(JSON.stringify())；

// 特别复杂的数据结构的深拷贝方法建议使用：Loadsh.cloneDeep()；

// JSON.parse(JSON.stringify(obj))是最简单粗暴的深拷贝，能够处理JSON格式的所有数据类型，但是对于正则表达式类型、函数类型等无法进行深拷贝，而且会直接丢失相应的值，还有就是它会抛弃对象的constructor。也就是深拷贝之后，不管这个对象原来的构造函数是什么，在深拷贝之后都会变成Object。同时如果对象中存在循环引用的情况也无法正确处理:

// let a = [1, 2, 3];
// let b = [4, 5, 6];
// let c = a.concat(b);
// c[0] = 100;
// console.log(a[0]);

let a = [
  {
    a: 1,
  },
];
let b = [
  {
    a: 1,
  },
];
let c = a.concat(b);
c[0].a = 100;
console.log(a[0]);

function cloneDeep(value) {
  if (typeof value !== "object" || value === null) {
    return value;
  }
  const cache = new Map();

  function _cloneDeep(value) {
    if (cache.has(value)) return cache.get(value);
    let obj = Array.isArray(value) ? [] : {};
    cache.set(value, obj);
    for (let key in value) {
      obj[key] = cloneDeep(value[key]);
    }
    return obj;
  }
  return _cloneDeep(value);
}

// test
const seven = {
  name: "seven",
};
const juejin = {
  name: "juejin",
  relative: seven,
};
seven.relative = juejin;
const newObj = cloneDeep(seven);
console.log(newObj);
